package com.cubeofnine.android.api;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.cubeofnine.android.api.contact.Address;
import com.cubeofnine.android.api.contact.Contact;
import com.cubeofnine.android.api.contact.ContactList;
import com.cubeofnine.android.api.contact.Email;
import com.cubeofnine.android.api.contact.IM;
import com.cubeofnine.android.api.contact.Organization;
import com.cubeofnine.android.api.contact.Phone;

import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;

public class ContactAPI extends ContactAbstractAPI {

	private Cursor cur;
	private ContentResolver cr;

	public Cursor getCur() {
		return cur;
	}

	public void setCur(Cursor cur) {
		this.cur = cur;
	}

	public ContentResolver getCr() {
		return cr;
	}

	public void setCr(ContentResolver cr) {
		this.cr = cr;
	}

	public Intent getContactIntent() {
		return (new Intent(Intent.ACTION_PICK,
				ContactsContract.Contacts.CONTENT_URI));
	}

	public ContactList newContactList() {
		ContactList contacts = new ContactList();
		String id;

		this.cur = this.cr.query(ContactsContract.Contacts.CONTENT_URI, null,
				null, null, null);
		if (this.cur.getCount() > 0) {
			while (cur.moveToNext()) {
				Contact c = new Contact();
				id = cur.getString(cur
						.getColumnIndex(ContactsContract.Contacts._ID));
				c.setId(id);
				c.setDisplayName(cur.getString(cur
						.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)));
				if (Integer
						.parseInt(cur.getString(cur
								.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) {
					c.setPhone(this.getPhoneNumbers(id));
				}
				c.setEmail(this.getEmailAddresses(id));
				c.setNotes(this.getContactNotes(id));
				c.setAddresses(this.getContactAddresses(id));
				c.setImAddresses(this.getIM(id));
				c.setOrganization(this.getContactOrg(id));
				contacts.addContact(c);
			}
		}
		return (contacts);
	}

	public boolean isContact(String displayName) throws Exception {
		boolean status = false;

		this.cur = this.cr.query(ContactsContract.Contacts.CONTENT_URI, null,
				ContactsContract.Contacts.DISPLAY_NAME + " = ?",
				new String[] { displayName }, null);
		if (this.cur.getCount() > 0) {
			status = true;
		}

		return status;
	}

	public boolean isGroup(String groupName) throws Exception {
		boolean status = false;

		this.cur = this.cr.query(ContactsContract.Groups.CONTENT_URI, null,
				ContactsContract.Groups.TITLE + " = ?",
				new String[] { groupName }, null);
		if (this.cur.getCount() > 0) {
			status = true;
		}

		return status;
	}

	public long getGroupIdByName(String groupName) throws Exception {
		long id = -1;
		this.cur = this.cr.query(ContactsContract.Groups.CONTENT_URI, null,
				ContactsContract.Groups.TITLE + " = ?",
				new String[] { groupName }, null);
		if (this.cur.getCount() > 0) {
			while (cur.moveToNext()) {
				id = cur.getLong(cur
						.getColumnIndex(ContactsContract.Groups._ID));
			}
		}

		return id;
	}

	public ArrayList<Phone> getPhoneNumbers(String id) {
		ArrayList<Phone> phones = new ArrayList<Phone>();

		Cursor pCur = this.cr.query(
				ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
				ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
				new String[] { id }, null);

		int type = -1;
		String label = "";
		while (pCur.moveToNext()) {
			type = pCur
					.getInt(pCur
							.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE));

			if (ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM == type) {
				label = pCur
						.getString(pCur
								.getColumnIndex(ContactsContract.CommonDataKinds.Phone.LABEL));
			} else if (ContactsContract.CommonDataKinds.Phone.TYPE_HOME == type) {
				label = "Home";
			} else if (ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE == type) {
				label = "Mobile";
			} else if (ContactsContract.CommonDataKinds.Phone.TYPE_WORK == type) {
				label = "Work";
			} else if (ContactsContract.CommonDataKinds.Phone.TYPE_FAX_WORK == type) {
				label = "Fax Work";
			} else if (ContactsContract.CommonDataKinds.Phone.TYPE_FAX_HOME == type) {
				label = "Fax Home";
			} else if (ContactsContract.CommonDataKinds.Phone.TYPE_PAGER == type) {
				label = "Pager";
			} else if (ContactsContract.CommonDataKinds.Phone.TYPE_OTHER == type) {
				label = "Other";
			} else if (ContactsContract.CommonDataKinds.Phone.TYPE_CALLBACK == type) {
				label = "Callback";
			} else if (ContactsContract.CommonDataKinds.Phone.TYPE_CAR == type) {
				label = "Car";
			} else if (ContactsContract.CommonDataKinds.Phone.TYPE_COMPANY_MAIN == type) {
				label = "Company Main";
			} else if (ContactsContract.CommonDataKinds.Phone.TYPE_ISDN == type) {
				label = "ISDN";
			} else if (ContactsContract.CommonDataKinds.Phone.TYPE_MAIN == type) {
				label = "Main";
			} else if (ContactsContract.CommonDataKinds.Phone.TYPE_OTHER_FAX == type) {
				label = "Other Fax";
			} else if (ContactsContract.CommonDataKinds.Phone.TYPE_RADIO == type) {
				label = "Radio";
			} else if (ContactsContract.CommonDataKinds.Phone.TYPE_TELEX == type) {
				label = "Telex";
			} else if (ContactsContract.CommonDataKinds.Phone.TYPE_TTY_TDD == type) {
				label = "TTY TDD";
			} else if (ContactsContract.CommonDataKinds.Phone.TYPE_WORK_MOBILE == type) {
				label = "Work Mobile";
			} else if (ContactsContract.CommonDataKinds.Phone.TYPE_WORK_PAGER == type) {
				label = "Work Pager";
			} else if (ContactsContract.CommonDataKinds.Phone.TYPE_ASSISTANT == type) {
				label = "Assistant";
			} else if (ContactsContract.CommonDataKinds.Phone.TYPE_MMS == type) {
				label = "MMS";
			}

			phones.add(new Phone(
					pCur.getString(pCur
							.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)),
					String.valueOf(type), label));
		}
		pCur.close();
		return (phones);
	}

	public ArrayList<Email> getEmailAddresses(String id) {
		ArrayList<Email> emails = new ArrayList<Email>();

		Cursor emailCur = this.cr.query(
				ContactsContract.CommonDataKinds.Email.CONTENT_URI, null,
				ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = ?",
				new String[] { id }, null);

		int type = -1;
		String label = "";
		while (emailCur.moveToNext()) {
			type = emailCur
					.getInt(emailCur
							.getColumnIndex(ContactsContract.CommonDataKinds.Email.TYPE));

			if (ContactsContract.CommonDataKinds.Email.TYPE_CUSTOM == type) {
				label = emailCur
						.getString(emailCur
								.getColumnIndex(ContactsContract.CommonDataKinds.Email.LABEL));
			} else if (ContactsContract.CommonDataKinds.Email.TYPE_HOME == type) {
				label = "Home";
			} else if (ContactsContract.CommonDataKinds.Email.TYPE_WORK == type) {
				label = "Work";
			} else if (ContactsContract.CommonDataKinds.Email.TYPE_OTHER == type) {
				label = "Other";
			} else if (ContactsContract.CommonDataKinds.Email.TYPE_MOBILE == type) {
				label = "Mobile";
			}

			// This would allow you get several email addresses
			Email e = new Email(
					emailCur.getString(emailCur
							.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA)),
					String.valueOf(type), label);

			emails.add(e);
		}
		emailCur.close();
		return (emails);
	}

	public ArrayList<String> getContactNotes(String id) {
		ArrayList<String> notes = new ArrayList<String>();
		String where = ContactsContract.Data.CONTACT_ID + " = ? AND "
				+ ContactsContract.Data.MIMETYPE + " = ?";
		String[] whereParameters = new String[] { id,
				ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE };
		Cursor noteCur = this.cr.query(ContactsContract.Data.CONTENT_URI, null,
				where, whereParameters, null);
		if (noteCur.moveToFirst()) {
			String note = noteCur
					.getString(noteCur
							.getColumnIndex(ContactsContract.CommonDataKinds.Note.NOTE));
			if (note.length() > 0) {
				notes.add(note);
			}
		}
		noteCur.close();
		return (notes);
	}

	public ArrayList<Address> getContactAddresses(String id) {
		ArrayList<Address> addrList = new ArrayList<Address>();

		String where = ContactsContract.Data.CONTACT_ID + " = ? AND "
				+ ContactsContract.Data.MIMETYPE + " = ?";
		String[] whereParameters = new String[] {
				id,
				ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE };

		Cursor addrCur = this.cr.query(ContactsContract.Data.CONTENT_URI, null,
				where, whereParameters, null);

		int type = -1;
		String label = "";
		while (addrCur.moveToNext()) {
			type = addrCur
					.getInt(addrCur
							.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.TYPE));
			if (ContactsContract.CommonDataKinds.StructuredPostal.TYPE_CUSTOM == type) {
				label = addrCur
						.getString(addrCur
								.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.LABEL));
			} else if (ContactsContract.CommonDataKinds.StructuredPostal.TYPE_HOME == type) {
				label = "Home";
			} else if (ContactsContract.CommonDataKinds.StructuredPostal.TYPE_WORK == type) {
				label = "Work";
			} else if (ContactsContract.CommonDataKinds.StructuredPostal.TYPE_OTHER == type) {
				label = "Other";
			}

			String poBox = addrCur
					.getString(addrCur
							.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.POBOX));
			String street = addrCur
					.getString(addrCur
							.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.STREET));
			String city = addrCur
					.getString(addrCur
							.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.CITY));
			String state = addrCur
					.getString(addrCur
							.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.REGION));
			String postalCode = addrCur
					.getString(addrCur
							.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE));
			String country = addrCur
					.getString(addrCur
							.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY));

			Address a = new Address(poBox, street, city, state, postalCode,
					country, String.valueOf(type), label);
			addrList.add(a);
		}
		addrCur.close();
		return (addrList);
	}

	public ArrayList<IM> getIM(String id) {
		ArrayList<IM> imList = new ArrayList<IM>();
		String where = ContactsContract.Data.CONTACT_ID + " = ? AND "
				+ ContactsContract.Data.MIMETYPE + " = ?";
		String[] whereParameters = new String[] { id,
				ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE };

		Cursor imCur = this.cr.query(ContactsContract.Data.CONTENT_URI, null,
				where, whereParameters, null);

		int type = -1;
		String label = "";
		while (imCur.moveToNext()) {
			type = imCur.getInt(imCur
					.getColumnIndex(ContactsContract.CommonDataKinds.Im.TYPE));
			if (ContactsContract.CommonDataKinds.Im.TYPE_CUSTOM == type) {
				label = imCur
						.getString(imCur
								.getColumnIndex(ContactsContract.CommonDataKinds.Im.LABEL));
			} else if (ContactsContract.CommonDataKinds.Im.TYPE_HOME == type) {
				label = "Home";
			} else if (ContactsContract.CommonDataKinds.Im.TYPE_WORK == type) {
				label = "Work";
			} else if (ContactsContract.CommonDataKinds.Im.TYPE_OTHER == type) {
				label = "Other";
			}

			String imName = imCur.getString(imCur
					.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA));

			if (imName.length() > 0) {
				IM im = new IM(imName, String.valueOf(type), label);
				imList.add(im);
			}
		}
		imCur.close();
		return (imList);
	}

	public ArrayList<Organization> getContactOrg(String id) {
		ArrayList<Organization> org = new ArrayList<Organization>();
		String where = ContactsContract.Data.CONTACT_ID + " = ? AND "
				+ ContactsContract.Data.MIMETYPE + " = ?";
		String[] whereParameters = new String[] { id,
				ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE };

		Cursor orgCur = this.cr.query(ContactsContract.Data.CONTENT_URI, null,
				where, whereParameters, null);

		int type = -1;
		String label = "";
		while (orgCur.moveToNext()) {
			type = orgCur
					.getInt(orgCur
							.getColumnIndex(ContactsContract.CommonDataKinds.Organization.TYPE));
			if (ContactsContract.CommonDataKinds.Organization.TYPE_CUSTOM == type) {
				label = orgCur
						.getString(orgCur
								.getColumnIndex(ContactsContract.CommonDataKinds.Organization.LABEL));
			} else if (ContactsContract.CommonDataKinds.Organization.TYPE_WORK == type) {
				label = "Work";
			} else if (ContactsContract.CommonDataKinds.Organization.TYPE_OTHER == type) {
				label = "Other";
			}

			String orgName = orgCur
					.getString(orgCur
							.getColumnIndex(ContactsContract.CommonDataKinds.Organization.DATA));
			String title = orgCur
					.getString(orgCur
							.getColumnIndex(ContactsContract.CommonDataKinds.Organization.TITLE));
			if (orgName.length() > 0) {
				Organization organization = new Organization(orgName, title,
						String.valueOf(type), label);
				org.add(organization);
			}
		}
		orgCur.close();
		return org;
	}

	public long createNewGroup(String groupName) throws Exception {
		long groupId = -1;

		if (groupName != null && !groupName.isEmpty() && !isGroup(groupName)) {
			ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();

			ops.add(ContentProviderOperation
					.newInsert(ContactsContract.Groups.CONTENT_URI)
					.withValue(ContactsContract.Groups.TITLE, groupName)
					.build());

			ContentProviderResult[] result = cr.applyBatch(
					ContactsContract.AUTHORITY, ops);
			try {
				groupId = Long
						.parseLong(result[0].uri.toString().split("/")[result[0].uri
								.toString().split("/").length - 1]);
			} catch (Exception e) {

			}
		}

		return groupId;
	}

	public long createNewContact(String displayName, String companyName,
			String jobTitle,
			List<com.cubeofnine.sugar.service.element.Phone> phones,
			List<com.cubeofnine.sugar.service.element.Email> emails,
			List<com.cubeofnine.sugar.service.element.Address> addresses)
			throws Exception {
		long contactId = -1;

		if (displayName != null && !displayName.isEmpty()
				&& !isContact(displayName)) {
			ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();

			ops.add(ContentProviderOperation
					.newInsert(ContactsContract.RawContacts.CONTENT_URI)
					.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
					.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)
					.build());

			// ------------------------------------------------------
			// Name
			ops.add(ContentProviderOperation
					.newInsert(ContactsContract.Data.CONTENT_URI)
					.withValueBackReference(
							ContactsContract.Data.RAW_CONTACT_ID, 0)
					.withValue(
							ContactsContract.Data.MIMETYPE,
							ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
					.withValue(
							ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
							displayName).build());

			// ------------------------------------------------------
			// Organization
			if (companyName != null && !companyName.isEmpty()) {
				if (jobTitle == null || jobTitle.isEmpty()) {
					jobTitle = "";
				}

				ops.add(ContentProviderOperation
						.newInsert(ContactsContract.Data.CONTENT_URI)
						.withValueBackReference(
								ContactsContract.Data.RAW_CONTACT_ID, 0)
						.withValue(
								ContactsContract.Data.MIMETYPE,
								ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE)
						.withValue(
								ContactsContract.CommonDataKinds.Organization.COMPANY,
								companyName)
						.withValue(
								ContactsContract.CommonDataKinds.Organization.TYPE,
								ContactsContract.CommonDataKinds.Organization.TYPE_WORK)
						.withValue(
								ContactsContract.CommonDataKinds.Organization.TITLE,
								jobTitle)
						.withValue(
								ContactsContract.CommonDataKinds.Organization.TYPE,
								ContactsContract.CommonDataKinds.Organization.TYPE_WORK)
						.build());
			}

			// ------------------------------------------------------
			// Phone
			if (phones != null) {
				int phoneType;
				String phoneNumber;
				com.cubeofnine.sugar.service.element.Phone phone = null;
				Iterator<com.cubeofnine.sugar.service.element.Phone> phoneIter = phones
						.iterator();
				while (phoneIter.hasNext()) {
					phone = phoneIter.next();
					phoneNumber = phone.getPhone_value();
					if (phoneNumber != null && !phoneNumber.isEmpty()) {
						try {
							phoneType = Integer.parseInt(phone.getPhone_type(),
									10);
						} catch (Exception e) {
							phoneType = ContactsContract.CommonDataKinds.Phone.TYPE_OTHER;
						}

						ops.add(ContentProviderOperation
								.newInsert(ContactsContract.Data.CONTENT_URI)
								.withValueBackReference(
										ContactsContract.Data.RAW_CONTACT_ID, 0)
								.withValue(
										ContactsContract.Data.MIMETYPE,
										ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
								.withValue(
										ContactsContract.CommonDataKinds.Phone.NUMBER,
										phoneNumber)
								.withValue(
										ContactsContract.CommonDataKinds.Phone.TYPE,
										phoneType).build());
					}
				}
			}

			// ------------------------------------------------------
			// Email
			if (emails != null) {
				int emailType;
				String emailAddress;
				com.cubeofnine.sugar.service.element.Email email = null;
				Iterator<com.cubeofnine.sugar.service.element.Email> emailIter = emails
						.iterator();
				while (emailIter.hasNext()) {
					email = emailIter.next();
					emailAddress = email.getEmail_value();
					if (emailAddress != null && !emailAddress.isEmpty()) {
						try {
							emailType = Integer.parseInt(email.getEmail_type(),
									10);
						} catch (Exception e) {
							emailType = ContactsContract.CommonDataKinds.Email.TYPE_OTHER;
						}

						ops.add(ContentProviderOperation
								.newInsert(ContactsContract.Data.CONTENT_URI)
								.withValueBackReference(
										ContactsContract.Data.RAW_CONTACT_ID, 0)
								.withValue(
										ContactsContract.Data.MIMETYPE,
										ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
								.withValue(
										ContactsContract.CommonDataKinds.Email.DATA,
										emailAddress)
								.withValue(
										ContactsContract.CommonDataKinds.Email.TYPE,
										emailType).build());
					}
				}
			}

			// ------------------------------------------------------
			// Address
			if (addresses != null) {
				int addressType;
				String street;
				String city;
				String state;
				String postalcode;
				String country;
				com.cubeofnine.sugar.service.element.Address address = null;
				Iterator<com.cubeofnine.sugar.service.element.Address> addressIter = addresses
						.iterator();
				while (addressIter.hasNext()) {
					address = addressIter.next();
					street = address.getStreet();
					city = address.getCity();
					state = address.getState();
					postalcode = address.getPostalcode();
					country = address.getCountry();

					if ((street != null && !street.isEmpty())
							|| (city != null && !city.isEmpty())
							|| (state != null && !state.isEmpty())
							|| (postalcode != null && !postalcode.isEmpty())
							|| (country != null && !country.isEmpty())) {
						if (street == null || street.isEmpty()) {
							street = "";
						}

						if (city == null || city.isEmpty()) {
							city = "";
						}

						if (state == null || state.isEmpty()) {
							state = "";
						}

						if (postalcode == null || postalcode.isEmpty()) {
							postalcode = "";
						}

						if (country == null || country.isEmpty()) {
							country = "";
						}

						try {
							addressType = Integer.parseInt(
									address.getAddress_type(), 10);
						} catch (Exception e) {
							addressType = ContactsContract.CommonDataKinds.StructuredPostal.TYPE_OTHER;
						}

						ops.add(ContentProviderOperation
								.newInsert(ContactsContract.Data.CONTENT_URI)
								.withValueBackReference(
										ContactsContract.Data.RAW_CONTACT_ID, 0)
								.withValue(
										ContactsContract.Data.MIMETYPE,
										ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE)
								.withValue(
										ContactsContract.CommonDataKinds.StructuredPostal.STREET,
										street)
								.withValue(
										ContactsContract.CommonDataKinds.StructuredPostal.CITY,
										city)
								.withValue(
										ContactsContract.CommonDataKinds.StructuredPostal.REGION,
										state)
								.withValue(
										ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE,
										postalcode)
								.withValue(
										ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY,
										country)
								.withValue(
										ContactsContract.CommonDataKinds.StructuredPostal.TYPE,
										addressType).build());
					}
				}
			}

			// Asking the Contact provider to create a new contact
			ContentProviderResult[] result = cr.applyBatch(
					ContactsContract.AUTHORITY, ops);
			try {
				contactId = Long
						.parseLong(result[0].uri.toString().split("/")[result[0].uri
								.toString().split("/").length - 1]);
			} catch (Exception e) {

			}
		}

		return contactId;
	}

	public Uri setContactMembership(long contactId, long groupId) {
		unsetContactMembership(contactId, groupId);

		ContentValues values = new ContentValues();
		values.put(
				ContactsContract.CommonDataKinds.GroupMembership.RAW_CONTACT_ID,
				contactId);
		values.put(
				ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID,
				groupId);
		values.put(
				ContactsContract.CommonDataKinds.GroupMembership.MIMETYPE,
				ContactsContract.CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE);

		return cr.insert(ContactsContract.Data.CONTENT_URI, values);
	}

	public int unsetContactMembership(long contactId, long groupId) {
		String contact = String.valueOf(contactId);
		String group = String.valueOf(groupId);

		return cr
				.delete(ContactsContract.Data.CONTENT_URI,
						ContactsContract.CommonDataKinds.GroupMembership.RAW_CONTACT_ID
								+ " = ? AND "
								+ ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID
								+ " = ?", new String[] { contact, group });
	}
}
